package com.hengshan.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hengshan.common.enums.ReturnCode;
import com.hengshan.domain.entity.Menu;
import com.hengshan.domain.entity.User;
import com.hengshan.domain.vo.MetaVo;
import com.hengshan.domain.vo.PageVo;
import com.hengshan.domain.vo.RouterVo;
import com.hengshan.exception.SystemException;
import com.hengshan.mapper.MenuMapper;
import com.hengshan.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 权限表(Menu)表服务实现类
 *
 * @author muxijun
 * @since 2023-12-22 15:42:58
 */
@Service("menuService")
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    public static final int MENU_STATUS_ON = 1; // 菜单状态启用
    @Autowired
    private MenuMapper menuMapper;

    @Transactional
    public boolean deleteByIds(List<Integer> ids) {
        return removeBatchByIds(ids);
    }

    @Transactional
    public boolean deleteById(Integer id) {
        return removeById(id);
    }

    public List<Menu> getList(String name, Integer status) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(status != null,Menu::getStatus, status)
                .like(StringUtils.hasText(name), Menu::getName, name)
                .orderByAsc(Menu::getParentId)
                .orderByAsc(Menu::getOrderNum);
        return list(wrapper);
    }

    public Menu getOneById(Integer id) {
        return getById(id);
    }

    @Transactional
    public Menu add(Menu menu) {
        checkUnique(menu);
        save(menu);
        return getById(menu.getId());
    }

    @Transactional
    public Menu update(Menu menu) {
        checkUnique(menu);
        updateById(menu);
        return menu;
    }

    @Override
    public List<String> selectPermsByUser(User user) {
        List<String> perms = new ArrayList<>();
        //admin用户返回所有权限
        if (user.isAdmin()) {
            perms.add("*:*:*");
        } else {
            perms = menuMapper.selectPermsByUserId(user.getId(), MENU_STATUS_ON);
        }
        return perms;
    }

    @Override
    public List<Menu> selectMenusByUser(User user) {
        // admin用户返回所有菜单
        if (user.isAdmin()) {
            return selectAllMenus(null);
        } else {
            if (null != user) {
                return menuMapper.selectMenusByUserId(user.getId(), MENU_STATUS_ON);
            }
            return null;
        }
    }

    @Override
    public List<Menu> selectMenusByUserAndType(User user, List<String> types) {
        // admin用户返回所有菜单
        if (user.isAdmin()) {
            return selectAllMenus(null);
        } else {
            if (null != user && !CollectionUtils.isEmpty(types)) {
                return menuMapper.selectMenusByUserIdAndType(user.getId(), types, MENU_STATUS_ON);
            }
            return null;
        }
    }

    public List<Menu> selectAllMenus() {
        return selectAllMenus(null);
    }

    public List<Menu> selectAllMenus(List<String> types) {
        LambdaQueryWrapper<Menu> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Menu::getStatus, MENU_STATUS_ON)
                .in(!CollectionUtils.isEmpty(types), Menu::getType, types)
                .orderByAsc(Menu::getParentId)
                .orderByAsc(Menu::getOrderNum);
        return list(wrapper);
    }

    public void checkUnique(Menu menu) {
        //校验菜单
        if (StringUtils.hasText(menu.getName())) {
            boolean checkName = menuMapper.exists(new LambdaQueryWrapper<Menu>()
                    .eq(Menu::getName, menu.getName())
                    .ne(menu.getId()!=null, Menu::getId, menu.getId()));
            if (checkName) {
                throw new SystemException(ReturnCode.MENU_EXIST);
            }
        }
    }

    @Override
    public List<Integer> selectMenuIdsByRoleId(Integer roleId) {
        return menuMapper.selectMenuIdsByRoleId(roleId);
    }

    @Override
    public List<RouterVo> getRouters(User user) {
        //此处只需获取m1,m2目录类型菜单，排除按钮类型菜单
        List<Menu> mMenus = selectMenusByUserAndType(user, Arrays.asList("m1", "m2"));
        List<Menu> menuTree = builderMenuTree(mMenus);
        List<RouterVo> router = builderRouters(menuTree);
        return router;
    }

    /**
     * 递归构建前端路由
     *
     * @param menuTree 菜单树列表
     * @return 路由列表
     */
    public List<RouterVo> builderRouters(List<Menu> menuTree) {
        List<RouterVo> routers = new LinkedList<>();
        for (Menu menu : menuTree) {
            int parentId = menu.getParentId();
            String type = menu.getType();
            String isFrame = menu.getIsFrame();
            String path = menu.getPath();
            String component = menu.getComponent();
            // 名称首字母转大写
            String routerName = StringUtils.capitalize(path);
            RouterVo router = new RouterVo();
            router.setHidden(Boolean.parseBoolean(menu.getVisible()));
            router.setName(routerName);
            if (parentId == 0 && isFrame.equals("0")) {
                router.setPath("/" + path);
            } else {
                router.setPath(path);
            }
            router.setComponent(StringUtils.hasText(component) ? component : "Layout");
            String link = null;
            if (isFrame.equals("1")) {
                link = path;
            }
            router.setMeta(new MetaVo(menu.getName(), menu.getIcon(), false, link));
            List<Menu> cMenus = menu.getChildren();
            if (!CollectionUtils.isEmpty(cMenus) && "m1".equals(type)) {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(builderRouters(cMenus));
            }
            routers.add(router);
        }
        return routers;
    }

    @Override
    public List<Menu> builderMenuTree(List<Menu> menus) {
        // 过滤出顶层菜单列表 parentId=0
        List<Menu> topMenu = menus.stream().filter(menu -> menu.getParentId().equals(0)).collect(Collectors.toList());
        for (Menu m : topMenu) {
            List<Menu> children = getChildrenMenu(menus, m);
            if (!children.isEmpty()) {
                m.setChildren(children);
            }
        }
        return topMenu;
    }

    /**
     * 递归获取菜单的子菜单
     *
     * @param menus 菜单列表
     * @param menu  菜单
     */
    public List<Menu> getChildrenMenu(List<Menu> menus, Menu menu) {
        List<Menu> children = menus.stream().filter(m -> m.getParentId().equals(menu.getId())).collect(Collectors.toList());
        for (Menu m : children) {
            List<Menu> children2 = getChildrenMenu(menus, m);
            if (!children2.isEmpty()) {
                m.setChildren(children2);
            }
        }
        return children;
    }

}

